﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Weight.Base
{
   public  class BaseControls
    {
        private static BaseControls _instance;

        private const int CS_DropSHADOW = 131072;

        private const int GCL_STYLE = -26;

        private Process process = null;

        private IntPtr appWin;

        private bool isMove = false;

        private const int WM_SYSCOMMAND = 274;

        private const int SC_MAXIMIZE = 61488;

        private const int SC_MINIMIZE = 61472;

        private const int SC_RESTORE = 61728;

        public const int SW_HIDE = 0;

        public const int SW_SHOW = 5;

        public static BaseControls Instance
        {
            get
            {
                if (BaseControls._instance == null)
                {
                    BaseControls._instance = new BaseControls();
                }
                return BaseControls._instance;
            }
        }

        private BaseControls()
        {
        }

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern int SetClassLong(IntPtr hwnd, int nIndex, int dwNewLong);

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern int GetClassLong(IntPtr hwnd, int nIndex);

        public void Shade(Control control)
        {
            BaseControls.SetClassLong(control.Handle, -26, BaseControls.GetClassLong(control.Handle, -26) | 0x20000);
        }

        [DllImport("user32.dll")]
        public static extern bool SendMessage(IntPtr hwnd, int wMsg, int wParam, int lParam);

        [DllImport("user32.dll")]
        public static extern bool ReleaseCapture();

        public void Move(Control sender, MouseEventArgs e, bool doubleLeftMaximized = true, bool doubleRightClose = true)
        {
            if (e.Button == MouseButtons.Left && e.Clicks == 1)
            {
                BaseControls.ReleaseCapture();
                BaseControls.SendMessage(sender.Handle, 161, 2, 0);
                BaseControls.SendMessage(sender.Handle, 514, 0, 0);
            }
            else if ((e.Button == MouseButtons.Left && e.Clicks == 2) & doubleLeftMaximized)
            {
                object valueReflection = this.GetValueReflection(sender, "WindowState");
                if (valueReflection is FormWindowState)
                {
                    switch ((FormWindowState)valueReflection)
                    {
                        case FormWindowState.Maximized:
                            this.SetValueReflection(sender, FormWindowState.Normal, "WindowState");
                            break;
                        case FormWindowState.Normal:
                            {
                                Rectangle workingArea = Screen.PrimaryScreen.WorkingArea;
                                int width = workingArea.Width;
                                workingArea = Screen.PrimaryScreen.WorkingArea;
                                Size size = new Size(width, workingArea.Height);
                                this.SetValueReflection(sender, size, "MaximumSize");
                                this.SetValueReflection(sender, FormWindowState.Maximized, "WindowState");
                                break;
                            }
                    }
                }
            }
            else if ((e.Button == MouseButtons.Right && e.Clicks == 2) & doubleRightClose)
            {
                MethodInfo methodReflection = this.GetMethodReflection(sender, "Close");
                if ((object)methodReflection != null)
                {
                    methodReflection.Invoke(sender, null);
                }
                Thread.Sleep(200);
            }
        }

        public void Move(Control moveControl, Control downControl, bool doubleLeftMaximized = true, bool doubleRightClose = true)
        {
        }

        [DllImport("user32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
        public static extern int SetParent(IntPtr hWndChild, IntPtr hWndNewParent);

        [DllImport("user32", CharSet = CharSet.Ansi, EntryPoint = "FindWindowA", ExactSpelling = true, SetLastError = true)]
        public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

        [DllImport("user32.dll", CharSet = CharSet.Ansi, EntryPoint = "SendMessageA", ExactSpelling = true, SetLastError = true)]
        private static extern int SendMessage(int hwnd, int wMsg, int wParam, int lParam);

        [DllImport("shell32.dll", CharSet = CharSet.Ansi, EntryPoint = "ShellExecuteA", ExactSpelling = true, SetLastError = true)]
        private static extern int ShellExecute(int hwnd, string lpOperation, string lpFile, string lpParameters, string lpDirectory, int nShowCmd);

        [DllImport("user32.dll", EntryPoint = "GetWindowLongA", SetLastError = true)]
        public static extern long GetWindowLong(IntPtr hwnd, int nIndex);

        [DllImport("user32.dll ", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
        private static extern int ShowWindow(int hwnd, int nCmdShow);

        public void BindingApp(Control control, string appName)
        {
            try
            {
                ProcessStartInfo startInfo = new ProcessStartInfo(appName)
                {
                    UseShellExecute = true,
                    CreateNoWindow = true,
                    WorkingDirectory = "",
                    WindowStyle = ProcessWindowStyle.Hidden
                };
                this.process = Process.Start(startInfo);
                this.process.EnableRaisingEvents = true;
                while (this.process == null || this.process.MainWindowHandle == IntPtr.Zero)
                {
                    this.process.Refresh();
                    this.process.MainWindowHandle.ToInt32();
                    Thread.Sleep(100);
                }
                this.EmbedProcess(control);
            }
            catch
            {
                return;
            }
            control.Resize += this.Control_Resize;
            this.isMove = true;
        }

        private void EmbedProcess(Control control)
        {
            if (this.process != null && !(this.process.MainWindowHandle == IntPtr.Zero))
            {
                try
                {
                    this.appWin = this.process.MainWindowHandle;
                    IntPtr window = AppContainer.GetWindow(this.appWin, 2u);
                    Control control2 = Control.FromHandle(window);
                    if (control2 != null)
                    {
                        ((Form)control2).TopLevel = false;
                    }
                    AppContainer.SetParent(this.appWin, control.Handle);
                    AppContainer.ShowWindow(this.appWin, 5);
                    AppContainer.SetWindowLong(new HandleRef(control, this.appWin));
                    AppContainer.MoveWindow(this.process, control);
                }
                catch
                {
                }
            }
        }

        private void Control_Resize(object sender, EventArgs e)
        {
            Control control = sender as Control;
            if (this.isMove)
            {
                AppContainer.MoveWindow(this.process, control);
            }
        }

        public void KillApp()
        {
            try
            {
                this.isMove = false;
                if (this.appWin != IntPtr.Zero)
                {
                    AppContainer.PostMessage(this.appWin, 16u, 0u, 0u);
                    Thread.Sleep(500);
                    this.appWin = IntPtr.Zero;
                }
                this.process.Kill();
            }
            catch
            {
                if (this.process != null)
                {
                    this.process.Dispose();
                }
            }
        }

        public void KillProcessApp(string exe)
        {
            Process[] processesByName = Process.GetProcessesByName(Path.GetFileName(exe));
            Process[] array = processesByName;
            foreach (Process process in array)
            {
                try
                {
                    process.Kill();
                }
                catch
                {
                }
            }
        }

        public void SetValueReflection(Control control, object value, string propertyName)
        {
            Type type = control.GetType();
            PropertyInfo property = type.GetProperty(propertyName);
            if (property != (PropertyInfo)null)
            {
                property.SetValue(control, value, null);
            }
        }

        public object GetValueReflection(Control control, string propertyName)
        {
            object result = null;
            Type type = control.GetType();
            PropertyInfo property = type.GetProperty(propertyName);
            if (property != (PropertyInfo)null)
            {
                result = property.GetValue(control, null);
            }
            return result;
        }

        public MethodInfo GetMethodReflection(Control control, string methodName)
        {
            Type type = control.GetType();
            return type.GetMethod(methodName);
        }

        public Form ParentForm(Control control)
        {
            Form result = null;
            if (control != null && control.Parent != null)
            {
                if (control.Parent.GetType().BaseType.Name == "Form" || control.Parent.GetType().BaseType.Name == "LYFForm" ||
                   control.Parent.GetType().BaseType.Name == "FuncForm" || control.Parent.GetType().BaseType.Name == "ManagerForm"
                   || control.Parent.GetType().BaseType.Name == "RadiusFrm")
                {
                    result = (Form)control.Parent;
                }
                else
                {
                    this.ParentForm(control.Parent);
                }
                return result;
            }
            return null;
        }

        public Size GetPrimaryScreenWorkingArea()
        {
            Rectangle workingArea = Screen.PrimaryScreen.WorkingArea;
            int width = workingArea.Width;
            workingArea = Screen.PrimaryScreen.WorkingArea;
            return new Size(width, workingArea.Height);
        }
    }
}
